﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace library
{
    public class p2pResult
    {
        public Cache<p2pResultItem> Terms = new Cache<p2pResultItem>(200000);

        public void AddTerm(byte[] contextId, string term)
        {
            CacheItem<p2pResultItem> result = null;

            lock (Terms)
            {
                result = Terms.FirstOrDefault(x => Addresses.Equals(x.CachedValue.ContextId, contextId));

                if (result == null)
                    Terms.Add(new p2pResultItem { ContextId = contextId, Term = term });

                else
                {
                    if (term.Contains(result.CachedValue.Term))
                        result.CachedValue.Term = term;

                    else
                    {
                        result.CachedValue.ReturnedContent.Clear();

                        result.CachedValue.SearchResults.Clear();
                    }

                    result.Reset();
                }
            }

            
        }

        public int Sent(byte[] address, byte[] contextId)
        {
            CacheItem<p2pResultItem> res = null;

            lock (Terms)
            {
                res = Terms.FirstOrDefault(x => Addresses.Equals(x.CachedValue.ContextId, contextId));
            }

            if (res != null)
            {
                lock (res.CachedValue.ReturnedContent)
                {
                    var r = res.CachedValue.ReturnedContent.FirstOrDefault(y => Addresses.Equals(y.HitValue.Address, address));

                    if (r != null)
                        return r.Hits;
                }
            }
            
            return 0;
        }

        internal ValueHits<p2pPost> Get(byte[] contextId)
        {
            CacheItem<p2pResultItem> resultItem = null;

            lock (Terms)
                resultItem = Terms.FirstOrDefault(x => Addresses.Equals(x.CachedValue.ContextId, contextId));

            if (resultItem == null)
                return null;

            var tops = resultItem.CachedValue.SearchResults.Tops();

            var result = new ValueHits<p2pPost>();

            tops.ForEach(x =>
                {
                    var sent = Sent(x.HitValue.Address, contextId);

                    if (sent > 0)
                    {
                        if (x.Hits - sent > 0)
                            result.Add(new p2pPost(x.HitValue.Address, x.HitValue.targetAddress), x.Hits - sent);
                    }
                    else
                    {
                        result.Add(x);
                    }

                    lock (resultItem.CachedValue.ReturnedContent)
                        resultItem.CachedValue.ReturnedContent.Add(new p2pPost(x.HitValue.Address), x.Hits);
                });

            return result;
        }

        internal List<CacheItem<p2pResultItem>> AddResults(string term, ValueHits<p2pPost> posts)
        {
            List<CacheItem<p2pResultItem>> result = null;

            lock (Terms)
            {
                var bTerm = Utils.FromBase64String(term);

                result = Terms.
                    Where(
                            x =>
                                bTerm == null ?
                                term.Contains(x.CachedValue.Term) :
                                x.CachedValue.SearchResults.Any(y => Addresses.Equals(y.HitValue.Address, bTerm) ||
                                Addresses.Equals(y.HitValue.targetAddress, bTerm))
                        ).ToList();

                result.
                    ForEach(x => x.CachedValue.SearchResults.AddRange(posts));

            }

            return result;
        }

        internal void Reset(byte[] contextId)
        {
            CacheItem<p2pResultItem> result = null;

            lock (Terms)
                result = Terms.FirstOrDefault(x => Addresses.Equals(x.CachedValue.ContextId, contextId));

            if (result != null)
            {
                result.Reset();

                //result.CachedValue.ReturnedContent.Reset();
            }
        }
    }

    public class p2pResultItem
    {
        public string Term;

        public byte[] ContextId;

        public ValueHits<p2pPost> ReturnedContent = new ValueHits<p2pPost>();

        public ValueHits<p2pPost> SearchResults = new ValueHits<p2pPost>();
    }
}
